home *** CD-ROM | disk | FTP | other *** search
-
- The REXX/imc Technical Reference
-
- This reference contains information for programmers of functions and other
- utilities to be called by (or to call) the Rexx interpreter.
-
- Information for Rexx programmers can be found in rexx.summary, rexx.info and
- rexx.ref.
-
-
- 1. Writing executable functions for REXX
-
- Synopsis: #include "functions.h"
- #include "ext.h" /* optional */
-
- dictionary rxdictionary[]; /* optional */
-
- int rxfunction(name,argc)
- char *name;
- int argc;
-
- There are two general ways to package REXX functions:
-
- (a) with a single function in each file, and
- (b) with multiple functions in one file (this will be called a package).
-
- In case (a), a file called "foo.rxfn" will be called by the function call
- "foo()" in a REXX program. In case (b), REXX will need some help from the
- programmer in order to know when to load a package to call a particular
- function. This can be done in two ways:
-
- (b.i) Give the package multiple names, by using symbolic (or hard) links.
- That is, if a package contains two functions, to be called from REXX
- as "foo()" and "bar()", then it may be stored in "foo.rxfn" and
- linked to "bar.rxfn". Once either of foo() or bar() have been
- called, both will be loaded and can be used without problems.
-
- (b.ii) Give the package a name such as "foo_init.rxfn" and insist that the
- REXX programmer always calls "foo_init()" first before using any
- other function in the package. This function will typically just
- stack "0" and return, but in the meantime REXX will have loaded all
- the functions from the package so that they can be used by the
- program.
-
- The set of mathematical functions, rxmathfn.rxfn, is an example of the first
- method above, but since the interpreter is programmed to interpret "sin",
- "cos", etc. as symbolic links to "rxmathfn", those links do not need to be
- physically present.
-
- A single REXX function file should contain a public symbol called
- "rxfunction" declared as in the synopsis above, and no dictionary.
-
- A function package should contain a public symbol called "rxdictionary"
- declared as above, containing the names and addresses of all the functions.
- Each of the functions should be declared in the same way as "rxfunction"
- above. A package called "foo.rxfn" may, in addition, supply the symbol
- "rxfunction" to implement the function "foo()", but only if the name "FOO"
- is not in the dictionary.
-
- The definition of the dictionary structure is as follows (in "const.h",
- included from "functions.h"):
-
- typedef struct _dictionary {
- char *name;
- int (*function)();
- } dictionary;
-
- The elements of the structure are:
-
- - name The function's name, as it should be known to REXX, in the form of
- a null-terminated string. The name should be in uppercase.
- - function The address of the function; a value of type int (*)(char *,int).
-
- The last element of the array of dictionary structures should have both
- fields set to a NULL pointer.
-
- Once a function is called, it is loaded into the interpreter together will
- all the functions listed in the dictionary, if any, and future calls will
- not have to be loaded from a file.
-
- Each function receives as its parameters the name by which it was called and
- the number of arguments supplied in the Rexx call to the function. The name
- is given in upper case and without any leading directory names (for instance
- "/direct/file"(3) gives "FILE" as the name parameter). Because this is
- given it is possible to fill in the "function" elements of several directory
- entries with the same address: the C function at that address uses the name
- parameter to ascertain which Rexx function was used.
-
- Each function should delete all its arguments from the calculator stack,
- and then either return 0, or stack an answer and return 1. This condition
- is relaxed if an error occurs: the function should then either die or return
- a negative number indicating the error condition. A list of error numbers
- is defined in const.h, including Ecall for "Incorrect call to routine".
-
- The arguments are placed on the calculator stack in LIFO order; that is, the
- last argument will be the first to be unstacked. Each argument is either a
- string or a null argument. A null argument has its length set to -1.
-
- Useful functions, including functions to retrieve arguments and stack the
- answer, are the following:
-
- char *delete(len) int *len;
-
- Deletes a string from the calculator stack, and returns an address where it
- can be found. On return, len will be set to the length of the argument.
- The string is guaranteed to be followed by two bytes of available memory, so
- that it can be null-terminated if necessary, and the string may be written
- to. The string is not guaranteed to be null-terminated when it is
- unstacked. The string is not actually moved in memory, so it may be
- invalidated whenever the calculator stack is changed (that means that it may
- not be used as an argument to stack()). However, further calls to delete()
- will not corrupt the string.
-
- int getint(flag) int *flag;
-
- Deletes a string from the calculator stack, interprets it as an integer, and
- returns the result. If the string is not a number which can be held in an
- int variable, the function will die. If the string is not an integer and
- the flag is non-zero, the function will die, otherwise the number will be
- converted into the nearest integer.
-
- void stack(string,len) char *string; int len;
-
- Copies the given string of the given length on to the calculator stack.
-
- void stackint(i) int i;
-
- Stacks a string representing the integer i on the calculator stack.
-
- int isnull()
-
- Returns 1 if the next value to be unstacked is null, and zero otherwise.
-
- void die(rc) int rc;
-
- Raise the error whose code is rc. The interpreter will then either halt
- with diagnostics or signal to an appropriate label, according to the current
- settings of "SIGNAL ON". This function never returns to its caller.
-
- int num(minus,exp,zero,len) int *minus,*exp,*zero,*len;
-
- Attempts to extract a number from the top value on the calculator stack,
- returning it as a sequence of digits. The value is always left stacked. If
- unsuccessful, num returns a negative number (except when the top value is
- null, in which case num dies). Otherwise, num stores a sequence of digits
- in the workspace (see below), and returns the offset from the start of the
- workspace to the start of the sequence of digits (which always equals the
- old value of eworkptr). The value eworkptr is updated to point past the end
- of the sequence of digits. The length of the sequence is returned in len.
- If the number is zero, then zero is set to 1, and otherwise it is set to 0.
- If it is negative, then minus is set to 1, and otherwise 0. The exponent
- stored in exp is such that if a decimal point were placed between the first
- two digits of the sequence and the result were multiplied by ten to the
- power exp, then the original number would be recovered.
-
- void stacknum(num,len,exp,minus) char *num; int exp,len,minus;
-
- A sequence of digits starting at address num and of length len is formatted
- according to the Rexx rules for numerics and stacked. The exponent "exp" and
- sign "minus" are interpreted according to the rules in "num" above.
-
- char *varget(name,namelen,len) char *name; int varlen; int *len;
-
- The variable whose name is "name" and contains "namelen" characters is
- searched for in the current symbol table. If the name is a compound symbol
- or a stem, then the first character of the name must have bit 7 set. The
- name is used as-is, that is, it is not translated to upper case, and if it
- is a compound variable then no substitution occurs in the tail. A pointer
- to the variable's value is returned, and "len" is set to its length. If the
- variable has not been assigned a value then "len" and the result are zero
- and the null pointer, respectively. The copy of the value which is returned
- must not be changed in any way. It may be invalidated whenever the symbol
- table is changed (and may not be used as a parameter to varset()).
-
- void varset(name,namelen,value,len) char *name,*value; int namelen,len;
-
- The parameters "name" and "namelen" name a variable and satisfy the same
- conditions as in varget above. The parameters "value" and "len" describe
- the position and length respectively of a string which is to be assigned to
- the variable. The assignment always succeeds unless there is insufficient
- memory available, in which case the routine dies.
-
- Note: the variable name and the string may contain arbitrary characters, and
- neither is validated. If you assign a value to a simple symbol called, e.g.
- "blah" (in lower case) or "XYZ.123" (containing a dot), etc. then the
- symbol will not be accessible to the Rexx program, but it may be recovered
- using varget(), provided it has not been hidden or destroyed by a PROCEDURE
- instruction.
-
- Any other function from the Rexx source may be used, but they are [or
- perhaps are not!] described elsewhere. Try in the source itself...
-
- A function may use global data from Rexx. It may either #include "ext.h"
- (which defines all the global variables of the Rexx interpreter) or simply
- include declarations for the particular variables it uses. Some useful
- variables are:
-
- char *workptr; unsigned eworkptr,worklen;
-
- The workspace, which may be used freely by a function. The space starts at
- workptr, and is of maximum length worklen. The variable eworkptr may be
- used to hold the length of the data currently stored in the workspace.
-
- int precision,fuzz;
-
- The setting of "NUMERIC DIGITS", and precision minus the setting of "NUMERIC
- FUZZ", respectively. That is, "precision" holds the precision of ordinary
- calculations, and "fuzz" holds the precision of comparison operations.
-
- char numform;
-
- Zero if "NUMERIC FORM SCIENTIFIC" is in effect, and one if "NUMERIC FORM
- ENGINEERING".
-
- int ppc;
-
- The number of the instruction being interpreted.
-
- int rxstacksock;
-
- A file descriptor which is connected to the Rexx stack process via a socket.
-
- FILE *ttyin,*ttyout;
-
- Streams which may be used to communicate with the terminal.
-
-
- A Rexx memory structure (for example the workspace) may be extended using
- the macros mtest or dtest. These are called like functions, but note that
- some arguments are evaluated more or less than once.
-
- mtest(memptr,alloc,length,extend)
-
- Check that the desired length for the area, "length", is not greater than
- the actual length, "alloc". If it is, then attempt to reallocate the area,
- pointed to by "memptr", with "extend" more bytes than its previous length.
- The parameters memptr and alloc will be updated to reflect the new position
- and length of the area. The macro will die if not enough memory is
- available.
-
- dtest(memptr,alloc,length,extend)
-
- Perform mtest on the four arguments, but return 0 if the area did not move,
- and non-zero otherwise. In order to use this macro, the current function
- must contain variables:
-
- char *mtest_old;
- long mtest_diff;
-
- If the memory pointer has moved, then mtest_diff contains the difference
- (the new pointer minus the old).
-
-
- 2. Accessing the REXX stack
-
- (a) Initialising
-
- When the application which requires access to the stack initialises, or
- when it first wants to use the stack, it should do the following:
-
- i. If the environment variable RXSTACK is set, then a stack already
- exists and uses a socket whose name is the value of RXSTACK. This
- should always happen if the application is called from within
- REXX. The application may choose to use this stack, or create
- another.
- ii. In order to create a new stack, the application should run "rxque"
- and store the output. If the application prefers a particular
- filename for the stack socket, it should give that as a parameter
- to "rxque" and also set the environment variable RXSTACK to that
- name. The output from "rxque filename" will be the stack's process
- number in the format "%d\n". The output from "rxque" will be in
- the form "RXSTACK=%s RXSTACKPROC=%d". The "%s" in this format is
- the stack's socket name, and the "%d" is the stack's process number.
- The RXSTACK variable must be exported to the environment. The
- process number must be remembered, so that the stack can be
- terminated later.
- iii.When a socket name has been obtained, the application should
- connect to it a socket of type SOCK_STREAM. This socket will be
- used in all further communication with the stack.
-
- The stack obtained by the application in this way can be accessed by
- any other process, providing it knows the socket name and has
- permission to access it. This will usually be limited to descendants
- of the application. In particular, if the application executes the
- REXX interpreter, the interpreter will use the same stack.
-
- (b) Terminating
-
- If the application did not create the stack, it has nothing further to
- do. Otherwise it must kill the stack process (using the pid which was
- remembered earlier) with signal 15 (SIGTERM).
-
- In case the application crashes, the stack process will terminate after
- five minutes of inactivity if it finds that its parent no longer
- exists (that means that when the stack server is executed it should be
- executed as a child of the application, and not a grandchild or other
- descendant).
-
- (c) Communications
-
- There are three data types which may be communicated: commands, lengths
- and data. A command is a single character. A length is a sequence of
- six hex digits followed by a newline character: seven bytes in all.
- Data is an arbitrary sequence of characters of a pre-determined
- length. All communications are written unbuffered.
-
- Each communication with the stack Each is initiated by the application
- writing a command character down the socket. The possible command
- characters are as follows:
-
- N (for Number): The stack responds by writing a length down the
- socket, representing the number of items on the stack.
- S (for Stack): The stack expects the application to write a length
- value followed by a data item of that length. It stacks that data
- item in lifo order.
- Q (for Queue): The stack expects the application to write a length
- value followed by a data item of that length. It queues that data
- item in fifo order.
- G (for Get): The stack responds by writing the length of the top stack
- entry followed by its data, and removes the entry from the stack.
- P (for Peek): The stack responds by writing the length of the top stack
- entry followed by its data, but leaves the stack unchanged.
- D (for Drop): No further communication occurs, but the stack deletes
- its top entry.
- K (for Kill me): The stack expects the application to write a length
- value followed by one more byte. The length value is interpreted as
- the pid of a process, and the byte as a signal number. On receipt of
- this information, the stack server will (attempt to) kill the given
- process with the given signal. This command may be used to make an
- application allow the stack to catch up, in case some of the
- communications are still en route to the server (the Num command could
- also be used for this purpose).
-
- If the stack process receives an incorrect command value or encounters
- an error while reading from the socket, then the connection to the
- offending application will be broken immediately.
-
- 3. The REXX internal data structures
-
- REXX has several data structures including the program, the label table, the
- symbol table, and the program stack. Each is kept as a block of "malloc"ed
- memory which is grown dynamically as necessary (the "growing" is usually
- performed by the mtest and dtest macros, mentioned above).
-
- (a) The Source
-
- The source code is stored in memory as it appears in the REXX program
- on disk, except that newline characters are translated into zero bytes.
- The address of each line (numbered from 1 to the number of lines in the
- program) is stored in an array (which is another block of "malloc"ed
- memory), and accessed using the construction "source[num]". The
- zeroth element of source stores the file name of the source, which is
- stored in a separately allocated block of memory. The block allocated
- for the source itself is guaranteed to start at source[1].
-
- (b) The Program
-
- The "program", or preprocessed source, is stored as a list of
- instructions, and prog[num] is a structure containing details about the
- "num"th instruction. There are "stmts" instructions in this list. Note
- that "THEN", "ELSE" and "OTHERWISE" are counted as individual
- instructions, and that null clauses do not appear in the list of
- instructions. prog[0] contains some pointers to the starts of things
- (namely the block allocated for the tokenised program itself, the block
- allocated for the source, and the beginning of the first comment in the
- source). prog[stmts] is a null instruction which points to the end of
- the source.
-
- Each instruction is obtained from the source by removing all comments
- and labels; stripping all unnecessary blanks and collapsing multiple
- spaces into one; concatenating lines together whenever the continuation
- character "," appears; tokenising keywords into special characters, and
- translating "^" (the variant NOT operator) into "\" (the real NOT
- operator). The source is also checked for mismatched quotes, invalid
- labels and invalid characters during preprocessing.
-
- Whereas "source" always contains the source of the program being
- interpreted, "prog" can sometimes contain the list of instructions
- obtained from an "interpret" instruction. In this case, the source
- pointer in prog[0] is used instead of source[1] when freeing the source.
- Also, certain instructions (such as "call") are required to save the
- current program temporarily and go back to the original program, by
- searching for it on the program stack.
-
- The current instruction number within the program is stored in the global
- variable ppc. The current character position within the program line is
- stored in a local variable, often called lineptr.
-
- Each prog[num] consists of the following structure, called "program":
-
- int num; The line number in the source where the instruction
- originates - used when tracing source instructions.
- char *source; The start of this instruction in the source
- char *sourcend; The end of this instruction in the source
- int related; Reserved for future use
- char *line; The address of the tokenised instruction
-
- The source between "source" and "sourcend" is the current instruction
- including any comments on the same line but not including labels.
- Comments on separate lines and labels will appear after "sourcend" or
- before "source".
-
- (c) The Labels
-
- Labels within a program are separated off and stored in a table while
- the program is being preprocessed. The table is stored in a block of
- memory at address labptr and of length lablen. While the table is being
- built up the length of data so far is elapbtr. The table consists of
- the concatenation of elements in the following format:
-
- int total length of this element
- int instruction number of label
- char[] name of label, terminated with a zero character and padded [*]
-
- The last element in the table is followed by the integer zero.
-
- [*] In all the data structures used by REXX/imc, variable-length string
- entries are padded (with random bytes) to a multiple of 4 bytes, in
- order that later data is aligned to the Sun SPARCstation's requirements.
- The alignment is done by macros in const.h and may be changed.
-
- (d) The Calculator Stack
-
- The calculator stack is simply a list of values in temporary storage
- during the evaluation of an expression. Expressions are in effect
- translated to reverse polish notation (e.g. 1+2 becomes 1 2 +), with
- each operation stacking and removing values as appropriate. The stack
- is stored in a block of memory addressed by cstackptr and of cstacklen
- bytes. The total size of the data on the stack is ecstackptr. Each
- element on the stack consists of a string (padded as necessary [*])
- followed by its integer length.
-
- (e) The Workspace
-
- The workspace is a block of memory which is used by various parts of the
- interpreter to store transient data. It is addressed by workptr and is
- of length worklen. Some routines (especially num()) maintain the length
- of the currently stored data in eworkptr.
-
- (f) The Symbol Table
-
- The symbol table is a multiple-level associative array containing the
- definitions of all the REXX symbols which have been assigned values. It
- is stored in a block of memory addressed by vartab and of length varlen.
-
- Each level of the table is a separate entity, referring to the active
- variables of a program fragment which used the PROCEDURE instruction to
- hide the earlier levels, except that each level may contain pointers to
- earlier levels as a result of the PROCEDURE EXPOSE instruction.
-
- The start of each level is stored in the array varstk[] as an integer
- offset from the start of the entire table. The number of levels is
- varstkptr, and the number of elements in the array is varstklen. The
- total length of all current levels of the symbol table is
- varstk[varstkptr+1].
-
- Each level of the symbol table contains all currently active simple
- symbols and stems as a binary search tree. The elements of the tree are
- in the following format (as described by the varent data type):
-
- int total length of this element
- int position of the left child (as offset from start of level)
- int position of the right child (as offset from start of level)
- int length of the symbol's name
- int amount of memory allocated to hold the symbol's value
- int actual length of the symbol's value
- char[] the symbol's name, padded [*]
- char[] space for the symbol's value
-
- If the symbol is a stem, the terminating dot of the name is not stored,
- but the most significant bit of the first character of the name is set.
-
- If the length of the value is negative, then the symbol is considered
- to be undefined; it has been deleted by DROP or some other process.
-
- If the "amount of memory" element of the structure is negative, then
- this symbol is actually located in an earlier level; the negative value
- gives the level number, starting at -1 which means the earliest level
- (i.e. the first in the memory block).
-
- Each stem entry in the symbol table has a value containing a default
- value and a mini-symbol table. The default value is stored first, in
- the format:
-
- int the amount of space allocated to the default value
- int the actual length of the default value
- char[] space for the default value
-
- Immediately following that are entries for all the tails, in exactly the
- same format as for the main symbol table.
-
- (g) The Program Stack
-
- The program stack holds information relating to currently active control
- structures, e.g. function calls and DO-END blocks. It is stored in a
- block of memory addressed by pstackptr and of length pstacklen. The
- length of all data currently on the program stack is epstackptr. The
- stack holds a sequence of various entries in the following formats, and
- the number of entries in the current function is held in pstacklev:
-
- for a simple DO-END block (type 0), a SELECT block (type 2),
- a DO WHILE or DO FOREVER block or (type 8), a "struct minstack" entry:
-
- int stmt the statement number where the block started
- char *pos the character where the block started (used for finding the
- WHILE or UNTIL part of a repetitive DO instruction)
- int len the length of this structure (16)
- int type the type value (as mentioned above)
-
- for a repetitive DO with a control variable, an extended "struct
- minstack" entry:
-
- int stmt the statement number where the block started
- char *pos the character where the block started
- char[] the limit value, padded [*] (empty string for "no limit")
- int the length of the limit value
- char[] the step value, padded [*]
- int the length of the step value
- char[] the name of the control variable, padded [*]
- int the length of the control variable name
- int the value which appeared after FOR, or -1 for "no value"
- int len the total length of this structure
- int type the number 10.
-
- for a repetitive block introduced by "DO count", a "struct forstack" entry:
-
- int stmt the statement number where the block started
- char *pos the character where the block started
- int fornum the value specified after "DO"
- int len the length of this structure (20)
- int type the number 15.
-
- for an internal function call, a "struct procstack2" entry:
-
- int stmt the statement number where the function call ocurred
- char *csp the caller's cstackptr
- int ecsp the caller's ecstaclptr
- int csl the caller's cstacklen
- char trc the caller's trace flag
- char tim the caller's timestamp flag
- char form the caller's NUMERIC FORM (0 for SCIENTIFIC)
- the compiler will probably insert one byte here
- int digits the caller's NUMERIC DIGITS
- int fuzz the caller's "NUMERIC DIGITS minus NUMERIC FUZZ"
- long mic the caller's timestamp microseconds value
- long sec the caller's timestamp seconds value
- program *prg the program which was being interpreted at the time
- int stmts the number of statements in that program
- int len the length of this structure (52)
- int type the number 11, becoming 12 when the PROCEDURE instruction
- has been executed
- Note: the program is stored in case it was generated by "interpret"; if
- that is so then the "real" program will be reinstated before the call.
-
- for an external function call, a "struct procstack" entry:
-
- int stmt the statement number where the function call ocurred
- char *csp the caller's cstackptr
- int ecsp the caller's ecstaclptr
- int csl the caller's cstacklen
- char trc the caller's trace flag
- char tim the caller's timestamp flag
- char form the caller's NUMERIC FORM (0 for SCIENTIFIC)
- the compiler will probably insert one byte here
- int digits the caller's NUMERIC DIGITS
- int fuzz the caller's "NUMERIC DIGITS minus NUMERIC FUZZ"
- long mic the caller's timestamp microseconds value
- long sec the caller's timestamp seconds value
- program *prg the caller's program
- int stmts the caller's number of instructions
- int lines the caller's number of program lines
- char *src the caller's source
- char *lab the caller's labptr
- int lev the caller's pstacklev
- int len the length of this structure (68)
- int type the number 13.
-
- for an INTERPRET instruction, a "struct interpstack" entry:
-
- int stmt the statement number where the INTERPRET occurred
- program *prg the program which was being interpreted at the time
- int stmts the number of instructions in that program
- int len the length of this structure (20)
- int type the number 14.
-
- for a command typed during interactive trace mode, a "struct
- interactstack" entry (note that a "struct interpstack" entry also
- appears above this):
-
- int stmt the statement number where the interruption occurred
- char *csp the interrupted program's cstackptr
- int ecs the interrupted program's ecstackptr
- int csl the interrupted program's cstacklen
- int len the length of this structure (16)
- int type the number 16.
-
- Occasionally, the interpreter stacks a program line with the sole intent
- of having it appear in the traceback. Such an entry would be in the
- format of a "struct errorstack":
-
- int stmt the statement number where the error occurred
- program *prg the program where the error occurred
- int stmts the number of statements in this program
- int len the length of this structure (20)
- int type the number 20
-
- (h) The "Hash" Tables
-
- There are three "hash" tables, each arranged in a similar way to one
- level of the symbol table; however the value of each symbol in the hash
- table is a single void* pointer rather than a string of characters.
- There are three hash tables, each occupying a separate block of memory
- addressed by hashptr[i] and of length hashlen[i] (for i=0,1,2). They
- are used to store environment variables, details of open files, and
- details about loaded functions respectively. Each element of a hash
- table is arranged as follows (and as indicated in the "hashent" data
- type):
-
- int length of this element
- int position of the left child
- int position of the right child
- void* value of the element
- char[] name of the element, terminated by a zero byte and padded [*]
-
- The value of each element may be one of the following:
-
- In hash table 0: a pointer to the string "NAME=VALUE" which has been
- used in a putenv() call.
-
- In hash table 1: either a null pointer, or a pointer to a block of
- memory which contains a "struct fileinfo" followed by a zero-terminated
- filename (which may be empty if the file name is unknown). The "struct
- fileinfo" is described in const.h.
-
- In hash table 2: a pointer to a "funcinfo" structure containing the
- address of a loaded function. One of the functions loaded from each
- function package also contains the handle which was returned from
- dlopen().
-
- (i) The Signal Stack
-
- REXX stores the context of each invocation of the interpreter()
- function, so that it can be restored whenever an EXIT or a caught signal
- is encountered. The context is stored in the array sigstack[], which at
- any time has sigstacklen elements allocated to it. The number of the
- highest used element of sigstack[] is interplev. Each entry of the
- signal stack contains:
-
- short bits The combined bits for all SIGNAL ON traps which are on
- short bitson ...all SIGNAL ON traps which were executed at this level
- short callon ...all CALL ON traps which are on
- short delay ...all conditions which are delayed
- char type 1 if a "signal" trap just occurred, 2 if "call", 0 if none
- char which The number for the condition which just occurred (if any)
- char *data A description for for the condition which just occurred
- int ppc[6] The statement numbers to jump to for all the conditions
- or minus the statement number to flag with "label not
- found" if a condition occurs
- jmp_buf jmp The context of this level of the interpreter.
-
- Note: a negative number in ppc[i] means that the trap instruction for
- this condition named a non-existent label. -ppc[i] will be the
- statement number of this trap instruction. This means that we can
- delay the "label not found" error until it actually happens: moreover,
- we can include the condition trap instruction in the traceback.
- However, an interpreted condition trap instruction is not guaranteed to
- stay around, and therefore it is reported as an error immediately if it
- names a non-existent label.
-
- (j) The Shell's Hash Table
-
- The builtin shell keeps a record of where it found each command in a
- hash table (yes, a real one ;-) ). The variable "hashtable" points to
- an array of bucket pointers, and the variable "hashbuckets" holds the
- number of pointers in the table. A bucket pointer is null if there are
- no entries in the bucket; otherwise it points to a hashitem structure,
- representing the first item in the bucket. That item may in turn point
- to another item in the bucket. The items in each bucket are kept in
- alphabetical order, to reduce the average time taken for an unsuccessful
- search (or an insertion). Each item contains the following information:
-
- struct _hashitem *next The next item in the bucket, or null
- int hits Number of times this has been found
- int expense Position within $PATH
- int dot Whether dot occurred in the path before this
- int data Offset from end of header to data
- char[] The key; a string of characters ending with 0.
- char[] The data; another nul-terminated string.
-